package com.hksj.cockpit.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hksj.base.vo.PropertyVO;
import com.hksj.cockpit.dto.ComprehensiveCockpitDTO;
import com.hksj.cockpit.dto.ComprehensiveCockpitEnergyDTO;
import com.hksj.cockpit.mapper.LaboratoryIntegrationCockpitMapper;
import com.hksj.cockpit.vo.AlarmRecordVO;
import com.hksj.cockpit.vo.DeviceOverviewVO;
import com.hksj.common.core.common.Constants;
import com.hksj.common.core.common.SpecialityModelCodeEnum;
import com.hksj.common.core.util.DateUtil;
import com.hksj.ecm.dto.EnergyCockpitDTO;
import com.hksj.ecm.service.EnergyCockpitService;
import com.hksj.ecm.vo.EnergyTrendVO;
import com.hksj.vsm.query.SpecialityVideoDeviceQuery;
import com.hksj.vsm.service.VideoDeviceInfoService;
import com.hksj.vsm.vo.PlayVideoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author fjt
 * @data 2024/10/21 11:09
 * @describe 实验室综合驾驶舱
 */
@Slf4j
@Service
public class LaboratoryIntegrationCockpitService {

    @Autowired
    private VideoDeviceInfoService videoDeviceInfoService;
    @Autowired
    private EnergyCockpitService energyCockpitService;
    @Autowired
    private LaboratoryIntegrationCockpitMapper laboratoryIntegrationCockpitMapper;

    // 能源类型code: 水
    private static final String water = "water";
    // 能源类型code: 电
    private static final String electricity = "electricity";

    static final List<String> codeList = new ArrayList<>(20);
    static {
        codeList.add(SpecialityModelCodeEnum.computer_room_security.getCode());
        codeList.add(SpecialityModelCodeEnum.air_conditioning.getCode());
        codeList.add(SpecialityModelCodeEnum.medical_gas.getCode());
        codeList.add(SpecialityModelCodeEnum.differential_pressure.getCode());
        codeList.add(SpecialityModelCodeEnum.cleanliness.getCode());
        codeList.add(SpecialityModelCodeEnum.air_quality.getCode());
        codeList.add(SpecialityModelCodeEnum.energy_consumption.getCode());
        codeList.add(SpecialityModelCodeEnum.smart_lighting.getCode());
        codeList.add(SpecialityModelCodeEnum.uv_lamp_control.getCode());
        codeList.add(SpecialityModelCodeEnum.ammonia_monitor.getCode());
        codeList.add(SpecialityModelCodeEnum.liquid_nitrogen.getCode());
        codeList.add(SpecialityModelCodeEnum.special_facility_temperature_control_management.getCode());
        // VAV的专业特殊，有两个子专业：VAV房间和VAV变风柜，但是VAV的真实物理设备只需查VAV变风柜的设备即可
        codeList.add(SpecialityModelCodeEnum.vav_bfg.getCode());
        codeList.add(SpecialityModelCodeEnum.special_gas_leakage.getCode());
        codeList.add(SpecialityModelCodeEnum.wireless_leak_water.getCode());
        codeList.add(SpecialityModelCodeEnum.video_monitoring.getCode());

    }


    /**
     * 环境概览     空气质量的监测数据
     * @param dto
     * @return
     */
    public List<PropertyVO> selectDevice(ComprehensiveCockpitDTO dto) {
        dto.setCode(SpecialityModelCodeEnum.air_quality.getCode());
        List<PropertyVO> list = new ArrayList();
        //取指定专业，在线的设备中最新的一台设备
        String id = laboratoryIntegrationCockpitMapper.getFirstDevice(dto);
        if (ObjectUtil.isNotEmpty(id)) {
            list = laboratoryIntegrationCockpitMapper.query(id);
        }
        return list;
    }


    /**
     * 设备概览
     * @param dto
     * @return
     */
    public Map<String, String> deviceOverview(ComprehensiveCockpitDTO dto){
        List<DeviceOverviewVO> list = laboratoryIntegrationCockpitMapper.deviceOverview(dto);
        if (CollUtil.isEmpty(list)){
            return null;
        }

        //总设备数
        Integer total = list.size();
        //总设备在线数
        Integer online = Math.toIntExact(list.stream().filter(DeviceOverviewVO -> DeviceOverviewVO.getState().equals("online")).count());
        //总设备离线数
        Integer offline = Math.toIntExact(list.stream().filter(DeviceOverviewVO -> DeviceOverviewVO.getState().equals("offline")).count());
        //总设备未激活数
        Integer notActive = Math.toIntExact(list.stream().filter(DeviceOverviewVO -> DeviceOverviewVO.getState().equals("notActive")).count());

        // 视频监控的设备不在dev_device_instance表中，而是在hk_video_device表中，需求单独查，并加上
        com.hksj.base.vo.DeviceOverviewVO videoDeviceOverview = videoDeviceOverview(dto);
        if (ObjectUtil.isNotNull(videoDeviceOverview)){
            total = total + videoDeviceOverview.getTotal();
            online = online + videoDeviceOverview.getOnlineNum();
            offline = offline + videoDeviceOverview.getOfflineNum();
            notActive = notActive + videoDeviceOverview.getNotActiveNum();
        }

        //在线率、先检查检查设备总数是否为零
        String onlineRate = "0%";
        if (Constants.ZERO.equals(total)) {
            // 设定一个默认值或者返回一个特定的消息
            onlineRate = "0%";
        } else {
            onlineRate = online * 100 / total + "%";
        }
        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put("count", String.valueOf(total));
        map.put("online", String.valueOf(online));
        map.put("offline", String.valueOf(offline));
        map.put("notActive", String.valueOf(notActive));
        map.put("onlineRate", onlineRate);

        for (String code : codeList){
            // 设备在线数
            long onlineCount = list.stream().filter(item -> (code.equals(item.getCode()) && "online".equals(item.getState()))).count();
            // 设备总数
            long count = list.stream().filter(item -> code.equals(item.getCode())).count();
            map.put(code + "OnlineCount", String.valueOf(onlineCount));
            map.put(code + "Count", String.valueOf(count));
        }
        // map中加入视频监控的设备概况
        map.put(SpecialityModelCodeEnum.video_monitoring.getCode() + "OnlineCount", String.valueOf(videoDeviceOverview.getOnlineNum()));
        map.put(SpecialityModelCodeEnum.video_monitoring.getCode() + "Count", String.valueOf(videoDeviceOverview.getTotal()));

        return map;
    }


    /**
     * 查询当前处于报警中的全部报警信息
     * @param dto
     * @return
     */
    public List<AlarmRecordVO> alarmRecord(ComprehensiveCockpitDTO dto) {
        return laboratoryIntegrationCockpitMapper.alarmRecord(dto);
    }


    /**
     * 视频监控设备概览
     * @param dto
     * @return
     */
    public com.hksj.base.vo.DeviceOverviewVO videoDeviceOverview(ComprehensiveCockpitDTO dto){
        SpecialityVideoDeviceQuery query = new SpecialityVideoDeviceQuery();
        query.setSpecialityCode(SpecialityModelCodeEnum.video_monitoring.getCode());
        query.setPaths(dto.getPaths());
        query.setDepartmentItemValue(dto.getDepartmentItemValue());
        return videoDeviceInfoService.getDeviceOverview(query);
    }


    /**
     * 查询多个摄像头监控视频
     * @return
     */
    public List<PlayVideoVO> queryListPlayVideoInfo(ComprehensiveCockpitDTO dto){
        SpecialityVideoDeviceQuery query = new SpecialityVideoDeviceQuery();
        query.setSpecialityCode(SpecialityModelCodeEnum.video_monitoring.getCode());
        query.setState("online");
        // 取top4
        query.setPageSize(Constants.FOUR);
        query.setPaths(dto.getPaths());
        query.setDepartmentItemValue(dto.getDepartmentItemValue());
        Page<PlayVideoVO> page = videoDeviceInfoService.pagePlayVideoInfo(query);
        return page.getRecords();
    }


    /**
     * 能耗概览-用水和电的总量
     * @param dto
     * @return
     */
    public Map<String, BigDecimal> queryEnergyTotal(ComprehensiveCockpitEnergyDTO dto){
        Date startTime = null;
        // 统计时间类型(1=月;2=年)
        if (Constants.ONE_STR.equals(dto.getTimeType())){
            // 获取当前时间所在月份的第一天
            startTime = DateUtil.getFirstDayOfMonth();
        }
        if (Constants.TWO_STR.equals(dto.getTimeType())){
            // 获取当前时间所在年份的第一天
            startTime = DateUtil.getFirstDayOfYear();
        }
        // 当月、当年
        dto.setStartTime(startTime);
        dto.setEndTime(DateUtil.getYmdHms(DateUtil.getYmd() + " 23:59:59"));

        // 当月或当年的用水量
        CompletableFuture<BigDecimal> waterFuture = CompletableFuture.supplyAsync(() ->{
            EnergyCockpitDTO waterDTO = new EnergyCockpitDTO();
            BeanUtils.copyProperties(dto, waterDTO);
            waterDTO.setEnergyTypeCode(water);
            // 查询每个产品的能耗  产品id : 能耗值
            Map<String, Double> energyMap = energyCockpitService.queryTotalEnergy(waterDTO);
            if (CollUtil.isEmpty(energyMap)){
                return new BigDecimal("0.0");
            }
            // 计算总能耗
            Double total = energyMap.values().stream().mapToDouble(Double::doubleValue).sum();
            return new BigDecimal(total).setScale(1, BigDecimal.ROUND_HALF_UP);
        });

        // 当月或当年的用电量
        CompletableFuture<BigDecimal> electricityFuture = CompletableFuture.supplyAsync(() ->{
            EnergyCockpitDTO electricityDTO = new EnergyCockpitDTO();
            BeanUtils.copyProperties(dto, electricityDTO);
            electricityDTO.setEnergyTypeCode(electricity);
            // 查询每个产品的能耗  产品id : 能耗值
            Map<String, Double> energyMap = energyCockpitService.queryTotalEnergy(electricityDTO);
            if (CollUtil.isEmpty(energyMap)){
                return new BigDecimal("0.0");
            }
            // 计算总能耗
            Double total = energyMap.values().stream().mapToDouble(Double::doubleValue).sum();
            return new BigDecimal(total).setScale(1, BigDecimal.ROUND_HALF_UP);
        });

        Map<String, BigDecimal> map = new HashMap<>(2);
        map.put(water, waterFuture.join());
        map.put(electricity, electricityFuture.join());
        return map;
    }


    /**
     * 能耗概览-趋势查询
     * @param dto
     * @return
     */
    public Map<String, List<EnergyTrendVO>> energyTrend(ComprehensiveCockpitEnergyDTO dto){
        Date startTime = null;
        // 统计时间类型(1=月;2=年)
        if (Constants.ONE_STR.equals(dto.getTimeType())){
            // 获取当前时间所在月份的第一天
            startTime = DateUtil.getFirstDayOfMonth();
        }
        if (Constants.TWO_STR.equals(dto.getTimeType())){
            // 获取当前时间所在年份的第一天
            startTime = DateUtil.getFirstDayOfYear();
        }
        // 当月、当年
        dto.setStartTime(startTime);
        dto.setEndTime(DateUtil.getYmdHms(DateUtil.getYmd() + " 23:59:59"));

        // 用水趋势
        CompletableFuture<List<EnergyTrendVO>> waterFuture = CompletableFuture.supplyAsync(() ->{
            EnergyCockpitDTO waterDTO = new EnergyCockpitDTO();
            BeanUtils.copyProperties(dto, waterDTO);
            waterDTO.setEnergyTypeCode(water);
            List<EnergyTrendVO> waterList = energyCockpitService.energyTrend(waterDTO);
            Map<String, EnergyTrendVO> map =  new HashMap<>();
            if (CollUtil.isNotEmpty(waterList)){
                map = waterList.stream().collect(Collectors.toMap(p -> p.getUploadTime(), p -> p));
            }

            List<EnergyTrendVO> list = new ArrayList<>();
            List<LocalDate> dateList = null;
            DateTimeFormatter formatter = null;
            // 统计时间类型(1=月;2=年)
            if (Constants.ONE_STR.equals(dto.getTimeType())){
                // 获取指定时间段内的每一天
                dateList = DateUtil.getDatesInRange(DateUtil.convertToLocalDate(waterDTO.getStartTime()),
                        DateUtil.convertToLocalDate(waterDTO.getEndTime()));
                formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            }
            if (Constants.TWO_STR.equals(dto.getTimeType())){
                // 获取指定时间段内的每月第一天
                dateList = DateUtil.getEveryMonthInRange(DateUtil.convertToLocalDate(waterDTO.getStartTime()),
                        DateUtil.convertToLocalDate(waterDTO.getEndTime()));
                formatter = DateTimeFormatter.ofPattern("yyyy-MM");
            }

            DateTimeFormatter finalFormatter = formatter;
            Map<String, EnergyTrendVO> finalMap = map;
            dateList.forEach(date -> {
                String dateStr = date.format(finalFormatter);
                EnergyTrendVO trendVO = finalMap.get(dateStr);
                if (ObjectUtil.isNull(trendVO)){
                    trendVO = EnergyTrendVO.builder().uploadTime(dateStr).consumptionValue(new Double("0.00")).build();
                }
                list.add(trendVO);
            });
            // 按时间升序排序
            return list.stream().sorted(Comparator.comparing(EnergyTrendVO::getUploadTime,
                    Comparator.naturalOrder())).collect(Collectors.toList());
        });

        // 用电趋势
        CompletableFuture<List<EnergyTrendVO>> electricityFuture = CompletableFuture.supplyAsync(() ->{
            EnergyCockpitDTO electricityDTO = new EnergyCockpitDTO();
            BeanUtils.copyProperties(dto, electricityDTO);
            electricityDTO.setEnergyTypeCode(electricity);
            List<EnergyTrendVO> electricityList = energyCockpitService.energyTrend(electricityDTO);
            Map<String, EnergyTrendVO> map = new HashMap<>();
            if (CollUtil.isNotEmpty(electricityList)){
                map = electricityList.stream().collect(Collectors.toMap(p -> p.getUploadTime(), p -> p));
            }

            List<EnergyTrendVO> list = new ArrayList<>();
            List<LocalDate> dateList = null;
            DateTimeFormatter formatter = null;
            // 统计时间类型(1=月;2=年)
            if (Constants.ONE_STR.equals(dto.getTimeType())){
                // 获取指定时间段内的每一天
                dateList = DateUtil.getDatesInRange(DateUtil.convertToLocalDate(electricityDTO.getStartTime()),
                        DateUtil.convertToLocalDate(electricityDTO.getEndTime()));
                formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            }
            if (Constants.TWO_STR.equals(dto.getTimeType())){
                // 获取指定时间段内的每月第一天
                dateList = DateUtil.getEveryMonthInRange(DateUtil.convertToLocalDate(electricityDTO.getStartTime()),
                        DateUtil.convertToLocalDate(electricityDTO.getEndTime()));
                formatter = DateTimeFormatter.ofPattern("yyyy-MM");
            }

            DateTimeFormatter finalFormatter = formatter;
            Map<String, EnergyTrendVO> finalMap = map;
            dateList.forEach(date -> {
                String dateStr = date.format(finalFormatter);
                EnergyTrendVO trendVO = finalMap.get(dateStr);
                if (ObjectUtil.isNull(trendVO)){
                    trendVO = EnergyTrendVO.builder().uploadTime(dateStr).consumptionValue(new Double("0.00")).build();
                }
                list.add(trendVO);
            });
            // 按时间升序排序
            return list.stream().sorted(Comparator.comparing(EnergyTrendVO::getUploadTime, Comparator.naturalOrder())).collect(Collectors.toList());
        });

        Map<String, List<EnergyTrendVO>> map = new HashMap<>(2);
        map.put(water, waterFuture.join());
        map.put(electricity, electricityFuture.join());
        return map;
    }


}
